In ordinary programming languages, every variable and constant has a type. A type is a set of values together with a set of operations that can be performed on those values. For example, integer types represent a specific range of integer values. Floating-point types represent real numbers in a format similar to scientific notation. The representation includes two numbers: a significand (i.e., a mantissa, or fraction) and the exponent. The significand holds the significant bits of the number, and the exponent encodes the location of the radix point.
Some computer applications, such as real-time control systems, perform real number computations but cannot afford the computing cost of floating-point arithmetic. These applications commonly use fixed-point types, which represent real numbers using integers. Arithmetic operations such as addition and multiplication are performed exactly the same for both integer and fixed-point types, so operations are much cheaper than floating-point arithmetic.
Like floating-point types, fixed-point types also represent real numbers in a format similar to scientific notation. Fixed-point types use a stored integer (comparable to the significand) and a radix point (the negative of the exponent). However, unlike floating-point types, the radix point is encoded into the type and not stored as part of the value. The radix point cannot change, hence the name “fixed-point”.
Ordinary programming languages provide not only a set of types, but also a set of rules governing how these types can be combined in expressions. We call these rules type propagation rules. Type propagation rules typically specify, for each operator of the language, what combinations of input types are permissible, and what type the result will have. Without type propagation rules, the programmer must explicitly specify the type of each operation (as in assembly language). The type propagation rules together with the set of types supported by a language are collectively called a type system.